package com.pluto.order.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.pluto.order.bean.Order;
import com.pluto.order.config.OrderServiceConfig;
import com.pluto.order.feign.ProductFeignClient;
import com.pluto.order.service.OrderService;
import com.pluto.product.bean.Product;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;


@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	DiscoveryClient discoveryClient;

	@Autowired
	private RestTemplate restTemplate;

	@Autowired
	private LoadBalancerClient loadBalancerClient;

	@Autowired
	private ProductFeignClient productFeignClient;

	@SentinelResource(value = "createOrder", blockHandler = "createOrderFallback")
	@Override
	public Order createOrder(String productId, Long userId) {
		// Product product = getProductFromRemoteWithLoadBalancerByAnnotation(productId);
		Product product = productFeignClient.getProductById(productId);
		BigDecimal total = product.getPrice().multiply(new BigDecimal(product.getNum()));
		Order order = new Order();
		order.setId(1L);
		order.setTotalAmount(total);
		order.setUserId(userId);
		order.setNickname("瓦娘");
		order.setAddress("shanghai");
		order.setProductList(List.of(product));
		return order;
	}

	public Order createOrderFallback(String productId, Long userId, BlockException blockException) {
		log.error("createOrderFallback,productId:{},userId:{}", productId, userId, blockException);
		Order order = new Order();
		order.setId(0L);
		order.setTotalAmount(new BigDecimal(0));
		order.setUserId(userId);
		order.setNickname("未知用户");
		order.setAddress("未知地址");
		return order;
	}


	/**
	 * 自实现的远程调用，缺少负载均衡
	 *
	 * @param productId
	 * @return
	 */
	private Product getProductFromRemote(String productId) {
		// 1. 获取商品服务
		List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
		ServiceInstance serviceInstance = instances.get(0);
		String url = serviceInstance.getUri() + "/product/" + productId;
		log.info("url:{}", url);
		return restTemplate.getForObject(url, Product.class);
	}

	/**
	 * 使用LoadBalancerClient实现负载均衡
	 */
	private Product getProductFromRemoteWithLoadBalancer(String productId) {
		// 1. 获取商品服务
		ServiceInstance choose = loadBalancerClient.choose("service-product");
		String url = choose.getUri() + "/product/" + productId;
		log.info("url:{}", url);
		return restTemplate.getForObject(url, Product.class);
	}

	/**
	 * {@link OrderServiceConfig#restTemplate()}
	 * 见连接中配置的 @LoadBalanced 注解
	 */
	private Product getProductFromRemoteWithLoadBalancerByAnnotation(String productId) {
		// service-product 为服务名称，会自动使用负载均衡器
		String url = "http://service-product/product/" + productId;
		return restTemplate.getForObject(url, Product.class);
	}
}
